package com.github.dote.mio.event;

import com.github.dote.mio.client.IOClient;
import com.github.dote.mio.protocal.Packet;
import com.github.dote.mio.protocal.VoidData;
import com.github.dote.mio.util.JsonUtil;
import com.github.dote.mio.util.ReflectionUtil;

import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

public class EventManager {

    class EventEntry {

        private Queue<EventListener> eventQueue = new ConcurrentLinkedQueue();

        public Queue<EventListener> getQueue() {
            return eventQueue;
        }

        public void addEvent(EventListener eventListener) {
            eventQueue.add(eventListener);
        }

        public void clear() {
            eventQueue.clear();
        }
    }

    private ConnectionListener connectionListener = null;
    private ConnectionListener reconnectionListener = null;
    private DisconnectionListener disconnectionListener = null;
    private LostPacketListener lostPacketListener = null;

    private Map<String, EventEntry> eventEntrys =new ConcurrentHashMap<>();

    public EventManager() {
    }

    public void addConnectionListener(ConnectionListener connectionListener){
        this.connectionListener=connectionListener;
    }

    public void onConnect(IOClient client) {
        if (connectionListener != null)
            connectionListener.onConnect(client);
    }


    public void addReconnectionListener(ConnectionListener connectionListener){
        this.reconnectionListener=connectionListener;
    }

    public void onReconnect(IOClient client) {
        if (reconnectionListener != null)
            reconnectionListener.onConnect(client);
    }

    public void addDisconnectionListener(DisconnectionListener disconnectionListener){
        this.disconnectionListener=disconnectionListener;
    }

    public void onDisconnect(IOClient client) {
        if (disconnectionListener != null)
            disconnectionListener.onDisconnect(client);
    }

    public void addLostPacketListener(LostPacketListener lostPacketListener){
        this.lostPacketListener=lostPacketListener;
    }

    public void onLostPacket(IOClient client, Packet packet) {
        if (lostPacketListener != null)
            lostPacketListener.onLostPacket(client, packet);
    }


    public void addEventListener(String eventName, EventListener eventListener) {
        if (!eventEntrys.containsKey(eventName)) {
            EventEntry eventEntry = new EventEntry();
            eventEntrys.put(eventName, eventEntry);
        }
        EventEntry ee = eventEntrys.get(eventName);
        ee.addEvent(eventListener);
    }

    public void removeEventListener(String eventName) {
        if (eventEntrys.containsKey(eventName)) {
            EventEntry eventEntry = new EventEntry();
            eventEntry.clear();
        }
    }

    public void onEvent(IOClient client, String eventName, String dataOfJsonString) {
        if (eventName == null || "".equals(eventName))
            return;
        if (dataOfJsonString == null || "".equals(dataOfJsonString))
            return;
        if (eventEntrys.containsKey(eventName)) {
            EventEntry eventEntry = eventEntrys.get(eventName);
            Queue<EventListener> eeQueue = eventEntry.getQueue();
            Iterator iterable = eeQueue.iterator();
            while (iterable.hasNext()) {
                EventListener listener = (EventListener) iterable.next();
                Object data = getEventData(dataOfJsonString, listener);
                if (data != null) {
                    listener.onEvent(client, data);
                }
            }
        }
    }

    public void onEvent(IOClient client, String eventName, Object data) {
        if (eventName == null || "".equals(eventName))
            return;
        if (data == null)
            return;
        if (eventEntrys.containsKey(eventName)) {
            EventEntry eventEntry = eventEntrys.get(eventName);
            Queue<EventListener> eeQueue = eventEntry.getQueue();
            Iterator iterable = eeQueue.iterator();
            while (iterable.hasNext()) {
                EventListener listener = (EventListener) iterable.next();
                Class clazz = getEventListenerClazz(listener);
                if (data != null && clazz == data.getClass()) {
                    listener.onEvent(client, data);
                }
            }
        }
    }

    /**
     * 获取事件值 json 转obj
     *
     * @param jsonString
     * @param dataListener
     * @return
     */
    private Object getEventData(String jsonString, EventListener<?> dataListener) {
        if (jsonString == null || "".equals(jsonString))
            return new VoidData();
        Class clazz = getEventListenerClazz(dataListener);
        return JsonUtil.parseObject(jsonString, clazz);
    }

    private Class getEventListenerClazz(EventListener<?> dataListener) {
        Class clazz = ReflectionUtil.getSuperInterfaceGenricType(dataListener.getClass(), 0, 0);
        return clazz;
    }
}
